package cn.fsw.pethome.base.service.impl;

import cn.fsw.pethome.base.domain.dto.BinderDTO;
import cn.fsw.pethome.base.domain.dto.LoginDTO;
import cn.fsw.pethome.base.domain.dto.WechatDTO;
import cn.fsw.pethome.base.service.ILoginService;
import cn.fsw.pethome.constants.BaseConstants;
import cn.fsw.pethome.jwt.JwtUtils;
import cn.fsw.pethome.jwt.PayloadData;
import cn.fsw.pethome.jwt.RsaUtils;
import cn.fsw.pethome.org.domain.Employee;
import cn.fsw.pethome.org.mapper.EmployeeMapper;
import cn.fsw.pethome.system.domain.Menu;
import cn.fsw.pethome.system.mapper.MenuMapper;
import cn.fsw.pethome.user.domain.Logininfo;
import cn.fsw.pethome.user.domain.User;
import cn.fsw.pethome.user.domain.Wxuser;
import cn.fsw.pethome.user.mapper.LogininfoMapper;
import cn.fsw.pethome.user.mapper.UserMapper;
import cn.fsw.pethome.user.mapper.WxuserMapper;
import cn.fsw.pethome.user.service.IUserService;
import cn.fsw.pethome.util.AjaxResult;
import cn.fsw.pethome.util.BusinessException;
import cn.fsw.pethome.util.HttpClientUtils;
import cn.fsw.pethome.util.MD5Utils;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.security.PrivateKey;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class LoginServiceImpl implements ILoginService {
    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private WxuserMapper wxuserMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private IUserService userService;

    @Value("${jwt.rsa.pri}")
    private String pri;

    @Autowired
    private EmployeeMapper employeeMapper;
    @Autowired
    private MenuMapper menuMapper;


    @Override
    @Transactional
    public Map<String, Object> account(LoginDTO loginDTO) {
        if(StringUtils.isEmpty(loginDTO.getUsername())){
            throw new BusinessException("账号不能为空");
        }
        if(StringUtils.isEmpty(loginDTO.getPassword())){
            throw new BusinessException("密码不能为空");
        }
        if(StringUtils.isEmpty(loginDTO.getType())){
            throw new BusinessException("非法访问");
        }
        Logininfo logininfo = logininfoMapper.queryLogin(loginDTO);
        if(logininfo == null){
            throw new BusinessException("账号或密码错误");
        }
        /*对密码加密*/
        String salt = logininfo.getSalt();
        String password = logininfo.getPassword();
        String pwd = MD5Utils.encrypByMd5(loginDTO.getPassword() + salt);
        if(!password.equals(pwd)){
            throw new BusinessException("账号或密码错误");
        }
        /*生成token*/

        /*return GetToken(logininfo);*/
        return GetJWTToken(logininfo);
    }
    /*微信登录业务*/
    @Override
    public AjaxResult wechat(WechatDTO wechatDTO) {
        if(StringUtils.isEmpty(wechatDTO.getCode())
            || StringUtils.isEmpty(wechatDTO.getBinderUrl())){
            throw new BusinessException("非法登录");
        }
        String url = BaseConstants.WxConstants.GET_ACCESS_TOKEN_URL.replace("APPID",BaseConstants.WxConstants.APPID)
                .replace("SECRET",BaseConstants.WxConstants.SECRET)
                .replace("CODE",wechatDTO.getCode());
        String result = HttpClientUtils.httpGet(url);
        JSONObject jsonObject = JSONObject.parseObject(result);//json字符串转成json对象
        //获取access_token 和openid
        String access_token  = jsonObject.getString("access_token");
        String openid  = jsonObject.getString("openid");
       Wxuser wxuser =  wxuserMapper.selectByOpenId(openid);
       if(wxuser == null){
           String data =wechatDTO.getBinderUrl()+"?"+"access_token="+access_token+"&openid="+openid;
           return AjaxResult.ajaxResult().setSuccess(false).setMsg("NoBinder").setData(data);

       }
        Long userId = wxuser.getUserId();
        User user = userMapper.selectById(userId);
        Long logininfo_id = user.getLogininfo_id();
        Logininfo logininfo = logininfoMapper.selectById(logininfo_id);
        /*Map<String, Object> stringObjectMap = GetToken(logininfo);*/
        return AjaxResult.ajaxResult().setData(GetJWTToken(logininfo));
    }
    /*绑定的业务*/
    @Override
    public AjaxResult binder(BinderDTO binderDTO) throws Exception {
        if(StringUtils.isEmpty(binderDTO.getPhone())){
            throw new BusinessException("手机号不能为空");
        }
        if(StringUtils.isEmpty(binderDTO.getVerifyCode())){
            throw new BusinessException("验证码不能为空");
        }
        if(StringUtils.isEmpty(binderDTO.getAccess_token())){
            throw new BusinessException("非法访问");
        }
        if(StringUtils.isEmpty(binderDTO.getOpenid())){
            throw new BusinessException("非法访问");
        }
        String Key = BaseConstants.register.BINDER+binderDTO.getPhone();
        Object code = redisTemplate.opsForValue().get(Key);
        if(code == null){
            throw new BusinessException("验证码已失效");
        }
        if(!code.toString().split(":")[0].equalsIgnoreCase(binderDTO.getVerifyCode())){
            throw new BusinessException("验证码错误");
        }
        //通过Access_token和Openid获取用户信息
        String url = BaseConstants.WxConstants.GET_USER_URL.replace("ACCESS_TOKEN", binderDTO.getAccess_token())
                .replace("OPENID", binderDTO.getOpenid());
        /*获取微信用户信息*/
        String result = HttpClientUtils.httpGet(url);
        Wxuser wxuser = JSONObject.parseObject(result, Wxuser.class);

        User user = userMapper.selectByPhoneUser(binderDTO.getPhone());
        if(user == null){
            user = new User();
            user.setPassword("111");
            user.setPhone(binderDTO.getPhone());
            user.setUsername(binderDTO.getPhone());
            userService.add(user);
            //发短信
            String msg = "恭喜您已成功绑定,您的默认密码为:"+"111";
            /*SendMsgUtil.SendMsg(Key,binderDTO.getPhone(),msg);*/
            System.out.println(msg);
        }
        wxuser.setUserId(user.getId());
        wxuserMapper.add(wxuser);
        Logininfo logininfo = logininfoMapper.selectById(user.getLogininfo_id());
        /*生成token*/
        /*Map<String, Object> stringObjectMap = GetToken(logininfo);*/

        return AjaxResult.ajaxResult().setData(GetJWTToken(logininfo));
    }

    /*生成token方法*/
    private Map<String, Object> GetToken(Logininfo logininfo){
        /*生成token*/
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token,logininfo,30, TimeUnit.MINUTES);
        logininfo.setSalt("");
        logininfo.setPassword("");
        Map<String, Object> map = new HashMap();
        map.put("token",token);
        map.put("userinfo",logininfo);
        return map;
    }

    private Map<String,Object>GetJWTToken(Logininfo logininfo){
        Map<String, Object> map = new HashMap();
        try {
            //获取私钥
            PrivateKey privateKey = RsaUtils.getPrivateKey(JwtUtils.class.getClassLoader().getResource(pri).getFile());
            //获取token
            PayloadData payloadData = new PayloadData();
            if(logininfo.getType() ==1){
               User user = userMapper.selectByLoginId(logininfo.getId());
                payloadData.setUser(user);
            }else {
            Employee employee =  employeeMapper.selectByLoginId(logininfo.getId());
                payloadData.setAdmin(employee);
                List<String> sns = employeeMapper.selectBySn(logininfo.getId());
                payloadData.setPermissions(new HashSet<>(sns));//将list转为set
               List<Menu> menus = employeeMapper.selectMenuByEmployeeId(logininfo.getId());
                List<Long> collect = menus.stream().map(Menu::getParent_id).distinct().collect(Collectors.toList());
                /*查询父级目录*/
                List<Menu> pMenus = menuMapper.selectMenuByPId(collect);
                /*将子级装进去*/
                HashSet<Menu> menus1 = new HashSet<>(menus);
                /*将父级装进去*/
                menus1.addAll(pMenus);
                payloadData.setMenus(Tree(menus1));

            }
            String token = JwtUtils.generateTokenExpireInMinutes(payloadData, privateKey, 3000);
            map.put("token",token);
            map.put("menu",payloadData.getMenus());
            map.put("permissions",payloadData.getPermissions());

            if(payloadData.getUser() == null){
                map.put("userinfo",payloadData.getAdmin());
            }else {
                map.put("userinfo",payloadData.getUser());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    public Set<Menu> Tree(Set<Menu> set) {
        Set<Menu> tree = new HashSet<>();
        for (Menu menu : set) {
            if(menu.getParent_id() == null){
                tree.add(menu);
            }else {
                for (Menu menu1 : set) {
                    if(menu.getParent_id() == menu1.getId()){
                        menu1.getChildren().add(menu);
                    }
                }
            }
        }
        return tree;
    }
}
